#include "stdafx.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "standard/nstring.h"
//#include "standard/CThrowException.h"
#include "ado/public.h"
#include "ado/DbMysql.h"
#include "ado/Database.h"
#include "standard/DBConfig.h"

#define MAX_PARM_LEN 255;

Database::Database()
{   
	m_wheres.clear();
    m_sets.clear();
	m_inserts.clear();

    m_prefix = DbMysql::instance()->get_dbprefix();
    m_dbname = DbMysql::instance()->get_dbname();
}

std::map<unsigned long int, std::string> Database::getAllColumn(std::string classname)
{
    std::map<unsigned long int, std::string> field_arr;
    std::string que, prefix;
    
    classname = tolower_str(classname);
    
    que = "show columns from " + m_dbname + "." + m_prefix  + classname;
    if (field_arr.size() == 0) {
        field_arr = DbMysql::instance()->execute(que.c_str())->getArrayField();
    }
    
    return field_arr;
}

/**
 * getall:1 fetch all of field
 * getall:0 fetch mix of field
 */
// fetch columns of array
std::map<unsigned long int, std::string> Database::getColumnOfArr(
    std::string classname, 
    std::map<std::string, std::string> param_arr)
{
    std::map<unsigned long int, std::string> new_field_arr;
    std::map<std::string, std::string>::iterator param_itor;    
    unsigned long int f_num;
    
    for (f_num = 0, param_itor=param_arr.begin(); param_itor!=param_arr.end(); param_itor++) {
        if (!this->findColumn(param_itor->first, classname)) continue;
        new_field_arr[f_num] = param_itor->first;
        f_num++;
    }
        
    return new_field_arr;
}

/**
 * getall:0 fetch all of field
 * getall:1 fetch mix of field
 */
std::string Database::getColumnOfStr(
    std::string classname, 
    std::map<std::string, std::string> param_arr)
{
    std::map<std::string, std::string>::iterator param_itor;
    std::string field_str;
    
    for (param_itor=param_arr.begin(); param_itor!=param_arr.end(); ++param_itor) {
        if (!this->findColumn(param_itor->first, classname)) continue;
        field_str += param_itor->first + ",";
    }
    field_str = field_str.substr(0, field_str.length()-1);
    
    return field_str;
}

int Database::findColumn(std::string key, std::string classname)
{
    std::map<unsigned long int, std::string> field_arr;
    std::map<unsigned long int, std::string>::iterator field_itor;

    field_arr = this->getAllColumn(classname);        
    for (field_itor=field_arr.begin(); field_itor!=field_arr.end(); field_itor++) {
        if (key.compare(field_itor->second) == 0) return true;
    }        
    
    return false;
}


/**
"sdate>=? AND edate=?", yesterday_s.c_str(), "54545411"
 */
Database *Database::findByArray(const char *fmt, va_list vp)
{
	stackCh name;	//字段名
	stackCh operat;	//操作符
	stackCh connector;	//连接标志
	stackCh fmtStack;	//检查栈	
    stackConstChar val;	//字段值
 
    //testfunc();
    
	char buf[256];//存放最终返回结果	
	memset(buf, 0, sizeof(buf));
	
    //boost::pool<> pol(sizeof(char));//开启内存池
    
	//检查 fmt 有无错误, 并依序放入 fmtStack 栈中 (顺序)
	unsigned long int num=0;
	while (*fmt) {
	    if (*fmt == '?') num++;
		fmtStack.push(*fmt);
		*fmt++;
	}	
	//dump(fmtStack);
	
	for (unsigned long int i=0; i<num; i++) {
	    val.push(va_arg(vp, const char *));
	}
	
	//从栈中读取合法数据 （逆序）
	for (int i=0; !fmtStack.empty(); i++)
	{
		char ch;
		while((ch=fmtStack.top()) == ' ') fmtStack.pop();//跳过空格
		if (ch=='?')
		{		    
			///取得操作符 operat
			//goods_id=? AND goods_name!=? AND goods_name in?
			fmtStack.pop();	//弹出  “？” 号
			while((ch=fmtStack.top()) == ' ') fmtStack.pop();//跳过空格
						
			if (ch == '=') {
				operat.push(ch);//push '=' into stack
				fmtStack.pop(); //pop the fmt
				
				while ((ch=fmtStack.top()) == ' ') {
				    fmtStack.pop();//跳过空格
				}
				    
				if (ch=='>' || ch=='<' || ch=='!') {
				    operat.push(ch);
				    fmtStack.pop(); // pop the '>' | '<' | '!' from fmtStack
				}				
			} 
			else if (ch == '>') {
			    operat.push(ch);
			    fmtStack.pop();
			    
			    while ((ch=fmtStack.top()) == ' ') {
			        fmtStack.pop();//跳过空格
			    }    
			}
			else if (ch == '<') {
			    operat.push(ch);
			    fmtStack.pop();
			    			    
			    while ((ch=fmtStack.top()) == ' ') {
			        fmtStack.pop();//跳过空格
		        }
			}
			else {			
			    do {
				    ch = fmtStack.top();//get the top element
				    operat.push(ch);//pop the top element
				    fmtStack.pop();
			    } while (ch != ' ');									
			    operat.pop();//去掉空格或等号	
			}	
						
			///取得 字段名 name
			while ((ch=fmtStack.top()) == ' ') fmtStack.pop();//跳过空格

			do {
				ch = fmtStack.top();
				name.push(ch);
				fmtStack.pop();
			} while (!fmtStack.empty() && ch && ch != ' ');
			
			///取得连接符 connector 
			if (!fmtStack.empty())
			{
			    name.pop();//去掉空格				
				while ((ch=fmtStack.top()) == ' ') fmtStack.pop();//跳过空格
                
				do {
					ch = fmtStack.top();
					connector.push(ch);
					fmtStack.pop();
				} while (!fmtStack.empty() && ch != ' ');
				
				connector.pop();//去年空格							
			}
			
			//拼接 name			
			sprintf(buf, "%s`", buf); 
			for (unsigned long int i=0; !name.empty(); i++)
			{
				sprintf(buf, "%s%c", buf, name.top());
				name.pop();
			}
			sprintf(buf, "%s` ", buf);
						
			//拼接 operat (in, >, <, =, like)
			char operat_ch[5];
			memset(operat_ch, 0, 5);
			for (unsigned long int i=0; !operat.empty(); i++)
			{
				sprintf(buf, "%s%c", buf, operat.top());
				sprintf(operat_ch, "%s%c", operat_ch, operat.top());
				operat.pop();
			}
			
			//拼接 value
			std::string current_val;
						
			current_val.erase();
			current_val = val.top();
			if (strncmp(operat_ch, "in", 5) == 0) {

			    vectorStr cval_arr = explode(",", current_val);	
				//GetFunInstance("explode",cval_arr,",",current_val);
			    for (unsigned int i=0; i<cval_arr.size(); i++) {
					//int flag =0;
					//GetFunInstance("is_numric",flag,cval_arr[i]);
			        if (!is_numeric(cval_arr[i])) {
			            unsigned int cval_item_len = cval_arr[i].length();
			            char *cval_item = (char*) malloc(cval_item_len+11); 
			            
			            mysql_escape_string(cval_item, cval_arr[i].c_str(), cval_item_len);	         
			            cval_arr[i] = cval_item;

						if (cval_item) {
							free(cval_item);
							cval_item = NULL;
						}

			            cval_arr[i] = "'" + cval_arr[i] + "'";
			        }
			    }
			    current_val = implode(",", cval_arr);
			    //GetFunInstance("implode",current_val,",",cval_arr);
			    sprintf(buf, "%s (%s)", buf, current_val.c_str());
			} 
			else {
			    char *cval_item = (char*) malloc(current_val.length()+11); 
			    mysql_escape_string(cval_item, current_val.c_str(), current_val.length());

			    current_val = cval_item;
			    sprintf(buf, "%s '%s'", buf, current_val.c_str());


			    if (cval_item) {
					free(cval_item);
					cval_item = NULL;
				}
			}
			val.pop();
						
			//拼接 connector
			sprintf(buf, "%s ", buf);
			for (unsigned long int i=0; !connector.empty(); i++) {
				sprintf(buf, "%s%c", buf, connector.top());
				connector.pop(); 
			}
			sprintf(buf, "%s ", buf);
		}	
			
		while (!fmtStack.empty() && (ch=fmtStack.top()) == ' ') {
		    fmtStack.pop();//跳过空格
		}
		
	}//for
	
	this->m_wheres = buf;
	this->m_wheres = trim(this->m_wheres);
	//std::cout<<"buf : "<<this->m_wheres<<std::endl;
	return this;
}//find

/**
    params["name"]        = "good";
    params["subject"]     = "test is ok";
    params["statu"]       = "999";
 */
Database *Database::insertparam(std::map<std::string, std::string> param_arr, std::string& classname)
{   
    std::map<std::string, std::string>::iterator param_itor;
    std::string pstr;
        
    //unsigned int cval_item_len;
    //boost::pool<> pol(sizeof(char));//开启内存池
    //std::string cval_str;    
    char *cval_item = NULL;
    unsigned int param_len = 0; 
              
    for (param_itor=param_arr.begin(); param_itor!=param_arr.end(); param_itor++) {
        if (!this->findColumn(param_itor->first, classname)) continue;

        param_len = (param_itor->second).length()*2;
        cval_item = new char[param_len*2];
        memset(cval_item, 0, param_len*2);
        mysql_escape_string(cval_item, (param_itor->second).c_str(), (param_itor->second).length());			            
        param_itor->second = cval_item;		

        std::string param_val(param_itor->second);
        param_val = trim(param_val);
		//GetFunInstance("trim",param_val,param_val);
        if (param_val[0] == '{' && param_val[param_val.length()-1] == '}') {    
            param_val = param_val.substr(1, param_val.length()-2);    	                  
            pstr += param_val + ",";               
        } else {                       
            pstr += "'" + param_val + "',";
        }
        delete [] cval_item; 
    }   
       
    this->m_inserts = pstr.substr(0, pstr.length()-1);            

    return this;
}

/**
    params["name"]        = "good";
    params["subject"]     = "test is ok";
    params["statu"]       = "999";
 */
Database *Database::setparam(std::map<std::string, std::string> param_arr, std::string& classname)
{   
    std::map<std::string, std::string>::iterator param_itor;
    std::string pstr;
        
    //unsigned int cval_item_len;

#if defined(__GNUC__)
//	boost::pool<> pol(sizeof(char));//开启内存池
#endif


#if defined(_MSC_VER)

#endif

	std::string cval_str;
	for (param_itor=param_arr.begin(); param_itor!=param_arr.end(); param_itor++) {
		if (!this->findColumn(param_itor->first, classname)) continue;
		int param_len = (param_itor->second).length()*2;

		char *cval_item = (char*) malloc(param_len); 
		memset(cval_item, 0, sizeof(cval_item));
		mysql_escape_string(cval_item, (param_itor->second).c_str(), (param_itor->second).length());
			
		param_itor->second = cval_item;		
		
		std::string param_val(param_itor->second);
		param_val = trim(param_val);
		//GetFunInstance("trim",param_val,param_val);
		if (param_val[0] == '{' && param_val[param_val.length()-1] == '}') {
			param_val = param_val.substr(1, param_val.length()-2);
			pstr += param_itor->first + "=" + param_val + ",";
		} 
		else {
			pstr += param_itor->first + "='" + param_val + "',";
		}
		delete [] cval_item; 
	}

	this->m_sets = pstr.substr(0, pstr.length()-1);
	return this;
}

std::string Database::getWhere()
{
	return this->m_wheres;
}

std::string Database::getSet()
{
	return this->m_sets;
}

std::string Database::getInsert()
{
	return this->m_inserts;
}

Database::~Database()
{

}

